package com.augurit.smartform.database;

import java.sql.Clob;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.augurit.common.util.lang.DateUtils;
import com.augurit.common.util.lang.StringUtils;
import com.augurit.smartform.database.change.ColumnChangeInfo;
import com.augurit.smartform.database.change.CopyDataInfo;
import com.augurit.smartform.database.change.DatabaseChange;
import com.augurit.smartform.exception.FormException;
import com.augurit.smartform.exception.FormNotUniqueException;
import com.augurit.smartform.factory.DialectFactory;
import com.augurit.smartform.service.ISmartFormService;
import com.augurit.smartform.util.XMLHelper;

/**
 * 数据库操作类
 * @author cuigeqiang
 *
 */
@Component
@Transactional
public class DatabaseExecutor {
	@Autowired
	private DialectFactory dialectFactory;
	@Autowired
	private DatabaseParser dbParser;
	@Autowired
	private ISmartFormService smartFormService;
	@Autowired
	private DatabaseComparator databaseComparator;
	
	/**
	 * 检查并执行数据库相关操作
	 * @param parameters
	 * cuigeqiang
	 */
	public void execute(String user, String sourceXml) throws FormException{
		if(sourceXml != null && sourceXml.trim().length() > 0){
			if(this.checkDatabaseChange(sourceXml)){
				this.executeDatabase(user, sourceXml);
			}
		}
	}
	
	/**
	 * 检查是否修改数据库
	 * @param sourceXmlStr
	 * @return
	 * cuigeqiang
	 */
	public boolean checkDatabaseChange(String sourceXmlStr){
		boolean dbChange=false;
		try {
			Document document=DocumentHelper.parseText(sourceXmlStr);
			List<Element> elements=document.selectNodes("//object");
			for(Element element : elements){
				String dbRelation=element.attributeValue("dbRelation");
				if(StringUtils.isNotBlank(dbRelation)&&"true".equalsIgnoreCase(dbRelation)){
					dbChange=true;
					break;
				}
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return dbChange;
	}

	/**
	 * 顺序从数据库中加载TABLE
	 * @param table
	 * @return
	 */
	public List<Table> loadOldTables(Table table){
		List<Table> oldTable=null;
		String oldXml=this.getOldXml(table);
		if(StringUtils.isNotBlank(oldXml)){
			oldTable=dbParser.parseToAscTables(oldXml);
		}
		return oldTable;
	}
	
	/**
	 * 执行数据库相关操作
	 * @param map
	 * cuigeqiang
	 */
	private void executeDatabase(String user, String sourceXml) throws FormException{
		List<Table> deepTables=dbParser.parseToAscTables(sourceXml);
		this.injectParamsToTables(deepTables, user, sourceXml);
		
		Table currentTable=smartFormService.getCurrentTable(sourceXml, deepTables);
		
		List<Table> oldTables=this.loadOldTables(currentTable);
		if(oldTables==null&&currentTable!=null){
			oldTables=new ArrayList<Table>();
			if(currentTable.getParent()!=null){
				oldTables.add(currentTable.getParent());
			}
		}
		
		this.validateFormName(deepTables, oldTables);
		
		DatabaseChange databaseChanges=databaseComparator.comparator(deepTables, oldTables);
		
		this.createAny(databaseChanges);								//创建表和序列
		this.copyData(databaseChanges);									//将数据拷贝到新版本
		this.delColumn(databaseChanges);								//删除数据库列
		this.addColumn(databaseChanges);								//给数据库添加字段
		this.renameColumn(databaseChanges);								//更改数据库字段名称
		this.modifyColumn(databaseChanges);								//修改数据库列长度、精度、标度、默认值、是否为空、唯一键、索引等信息
		
		this.updateSysMetaTable(databaseChanges);						//统一更新SYSMETATABLE
	}
	
	/**
	 * 把参数注入到表单列表中
	 * @param deepTables
	 * @param params
	 * cuigeqiang
	 */
	private void injectParamsToTables(List<Table> deepTables, String user, String sourceXml){
		for(int i=0;i<deepTables.size();i++){
			Table table=deepTables.get(i);
			this.injectParamsToTable(table, user, sourceXml);
		}
	}
	
	/**
	 * 把参数注入到表单中
	 * @param table
	 * @param params
	 * cuigeqiang
	 */
	private void injectParamsToTable(Table table, String user, String sourceXml){
		table.setCreator(user);
//		table.setSourceXmlStr(sourceXml);
		table.setCreateTime(new Date());
	}
	
	/**
	 * 加载数据库的XML字符串
	 * @param table
	 * @return
	 * cuigeqiang
	 */
	private String getOldXml(Table table){
		return smartFormService.getOldXml(table);
	}
	
	/**
	 * 创建数据库表和序列
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void createAny(DatabaseChange databaseChanges){
		List<Table> createTables=databaseChanges.getCreateTables();
		for(int i=0;i<createTables.size();i++){
			Table table=createTables.get(i);
			smartFormService.executeCreateAny(table);
		}
	}
	
	/**
	 * 把数据从旧版本迁移到新版本
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void copyData(DatabaseChange databaseChanges){
		Set<Entry<String,CopyDataInfo>> set=databaseChanges.getCopyDataMap().entrySet();
		Iterator<Entry<String,CopyDataInfo>> it=set.iterator();
		while(it.hasNext()){
			Entry<String,CopyDataInfo> entry=it.next();
			if(entry.getValue()!=null){
				smartFormService.executeCopyData(entry.getValue());
			}
		}
	}
	
	/**
	 * 给数据库表增加列
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void addColumn(DatabaseChange databaseChanges){
		Map<String,ColumnChangeInfo> columnChangeInfos=databaseChanges.getColumnChangeInfos();
		Iterator<ColumnChangeInfo> it=columnChangeInfos.values().iterator();
		while(it.hasNext()){
			ColumnChangeInfo columnChangeInfo=it.next();
			smartFormService.executeAddColumn(columnChangeInfo);
		}
	}
	
	/**
	 * 给数据库表增加列
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void delColumn(DatabaseChange databaseChanges){
		Map<String,ColumnChangeInfo> columnChangeInfos=databaseChanges.getColumnChangeInfos();
		Iterator<ColumnChangeInfo> it=columnChangeInfos.values().iterator();
		while(it.hasNext()){
			ColumnChangeInfo columnChangeInfo=it.next();
			smartFormService.executeDelColumn(columnChangeInfo);
		}
	}
	
	/**
	 * 重命名数据库列
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void renameColumn(DatabaseChange databaseChanges){
		Map<String,ColumnChangeInfo> columnChangeInfos=databaseChanges.getColumnChangeInfos();
		Iterator<ColumnChangeInfo> it=columnChangeInfos.values().iterator();
		while(it.hasNext()){
			ColumnChangeInfo columnChangeInfo=it.next();
			smartFormService.executeRenameColumn(columnChangeInfo);
		}
	}
	
	/**
	 * 修改数据库列长度、精度、标度、默认值、是否为空、唯一键、索引等信息
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void modifyColumn(DatabaseChange databaseChanges){
		Map<String,ColumnChangeInfo> columnChangeInfos=databaseChanges.getColumnChangeInfos();
		Iterator<ColumnChangeInfo> it=columnChangeInfos.values().iterator();
		while(it.hasNext()){
			ColumnChangeInfo columnChangeInfo=it.next();
			smartFormService.executeModifyColumn(columnChangeInfo);
		}
	}
	
	/**
	 * 删除数据库表和序列
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void dropAny(DatabaseChange databaseChanges){
		List<Table> dropTables=databaseChanges.getDropTables();
		for(int i=0;i<dropTables.size();i++){
			Table table=dropTables.get(i);
			smartFormService.executeDropAny(table);
		}
	}
	
	/**
	 * 统一更新SYSMETATABLE
	 * @param databaseChanges
	 * cuigeqiang
	 */
	private void updateSysMetaTable(DatabaseChange databaseChanges){
		Map<String,ColumnChangeInfo> columnChangeInfos=databaseChanges.getColumnChangeInfos();
		Iterator<ColumnChangeInfo> it=columnChangeInfos.values().iterator();
		while(it.hasNext()){
			ColumnChangeInfo columnChangeInfo=it.next();
			smartFormService.updateSysMetaTable(columnChangeInfo);
		}
	}
	
	/**
	 * 验证表单名称是否合法
	 * @param deepTables
	 * @param oldTables
	 * cuigeqiang
	 * @throws FormNotUniqueException 
	 */
	private void validateFormName(List<Table> deepTables,List<Table> oldTables) throws FormNotUniqueException{
		if(oldTables!=null&&deepTables!=null&&oldTables.size()>0&&deepTables.size()>0){
			for(Table deepTable : deepTables){
				for(Table oldTable : oldTables){
					if(deepTable.getName().equalsIgnoreCase(oldTable.getName())){
						if(!deepTable.getPageId().equalsIgnoreCase(oldTable.getPageId())){
							throw new FormNotUniqueException("表单"+deepTable.getName());
						}
						break;
					}
				}
			}
		}
	}
	
}
